﻿/*****************************************介绍*****************************************
 * 作者：User
 * 创建时间：2025-09-09 17:00:47
 * 功能：真正玩游戏的数据
**************************************************************************************/

using Game.Framework;
using MessagePack;
using System.Collections.Generic;
using System.Linq;

public partial class GameDataModel
{
    // 单个关卡数据
    [MessagePackObject]
    public class Level
    {
        [Key(0)] public int level;
        [Key(1)] public int lifeRemainNum;                  // 生命数量（如果有）
        [Key(2)] public float remainSeconds;                // 剩余时间（如果有）
        [Key(3)] public EStyle style;                       // 格子图标风格
        [Key(4)] public string layout;                      // 布局类型
        [Key(5)] public List<Item> items;                   // 格子数据
        [Key(6)] public int destroyedCount;                 // 当前已消除的格子数量
        [Key(7)] public int reward;                         // 通关后的奖励
        [Key(8)] public int iconIdNum;                      // 格子图片的类型（ID）数量
        [Key(9)] public List<AssetInfo> assetsInfo;         // 资源信息
        [Key(10)] public int finalSelectIdx = -1;           // 最终选择的资源索引
        [Key(11)] public bool cantFreeRefresh;              // 是否不可以免费刷新
        [Key(12)] public int downloadAdCount;               // 下载照片已看广告次数
        [Key(13)] public ELevelStatus status;               // 当前关卡的状态（未解锁，已解锁，进行中）
        [Key(14)] public ELevelType type;                   // 当前关卡的类型（普通、特殊）
        [Key(15)] public ECollectStatus collectStatus;      // 收藏状态

        public Level() { }

        public Level(int level, string layout, int reward, int iconIdNum)
        {
            this.level = level;
            style = (EStyle)UnityEngine.Random.Range(0, 4);
            this.layout = layout;
            this.reward = reward;
            remainSeconds = GetTimeLimitLen();
            lifeRemainNum = GetErrorLimitLen();
            this.iconIdNum = iconIdNum;

            // 校验布局
            VerifyLayout();

            InitItems();
            EventCenter.Instance.Trigger(GameEventName.OnLifeCountChanged, lifeRemainNum);
        }

        private void VerifyLayout()
        {
            // 解析布局信息
            string[] dimensions = layout.Split('x');
            if (dimensions.Length != 2)
            {
                LogManager.LogError("无效的布局信息，请检查格式，如：4x4, 6x9，本次会使用默认布局：4x4");
                layout = "4x4";
                dimensions = layout.Split('x');
            }

            var colums = int.Parse(dimensions[0]);
            var rows = int.Parse(dimensions[1]);

            // 验证总数是否为偶数
            var totalCount = rows * colums;
            if (totalCount % 2 != 0)
            {
                LogManager.LogError($"布局不符合游戏规则，总数应该是偶数，当前为：{layout}={totalCount}，本次会使用默认布局：4x4");
                layout = "4x4";
            }
        }

        private List<int> GetRandomElements(int count)
        {
            if (count > 12) count = 12;

            List<int> randomElements = new List<int>();

            while (randomElements.Count < count)
            {
                int index = UnityEngine.Random.Range(0, 12); // 随机选择一个索引
                if (!randomElements.Contains(index))
                    randomElements.Add(index);
            }

            return randomElements;
        }

        /// <summary>获得错误限制长度</summary>
        private int GetErrorLimitLen()
        {
            if (!GameDataMgr.Instance.IsUnlockErrorLimit())
                return level >= BaseDataMgr.Instance.Cfg.props.error.unlock ? 3 : 0;
            else
                return 3;
        }

        /// <summary>获得时间限制长度</summary>
        private int GetTimeLimitLen()
        {
            var otherCfg = BaseDataMgr.Instance.Cfg.level.other_level;
            var cfg = level <= BaseDataMgr.Instance.Cfg.level.level_data.Length ? BaseDataMgr.Instance.Cfg.level.level_data[level - 1] : otherCfg;
            if (status != ELevelStatus.Completed || !GameDataMgr.Instance.IsUnlockTimeLimit())
                return cfg.time;
            else
                return cfg.time <= 0 ? otherCfg.time : cfg.time;
        }

        /// <summary>初始化所有格子</summary>
        public void InitItems()
        {
            destroyedCount = 0;
            lifeRemainNum = GetErrorLimitLen();
            remainSeconds = GetTimeLimitLen();

            int count = GetItemCount();
            if (items == null)
                items = new List<Item>(count);
            else
                items.Clear();
            // 总行数和总列数
            int rowCount = GetTotalRow();
            int colCount = GetTotalCol();

            // 创建所有格子
            List<int> iconIds = new List<int>();
            var iconElements = GetRandomElements(iconIdNum);
            int easyLv = UnityEngine.Mathf.Max(BaseDataMgr.Instance.Cfg.props.bomb.unlock, BaseDataMgr.Instance.Cfg.props.shuffle.unlock);
            for (int i = 0; i < count / 2; i++)
            {
                int iconId = -1;
                if (level <= easyLv)
                    iconId = UnityEngine.Random.Range(0, 3);
                else
                    iconId = i < iconElements.Count ? iconElements[i] : iconElements[UnityEngine.Random.Range(0, iconElements.Count)];
                iconIds.Add(iconId);
                iconIds.Add(iconId);
            }

            // 打乱顺序
            System.Random random = new System.Random();
            iconIds = iconIds.OrderBy(x => random.Next()).ToList();

            for (int i = 0; i < count; i++)
            {
                Item item = new Item
                {
                    id = i,
                    iconId = iconIds[i],
                    status = EItemStatus.Locked,
                };
                items.Add(item);
            }

            // 随机选择横向或纵向
            bool isVertical = status != ELevelStatus.Completed && level == 1 ? false : random.Next(2) == 0;
            // 中间的行或列
            int midCol = colCount / 2;
            int midRow = rowCount / 2;
            int midId1 = -1;
            int midId2 = -1;

            if (isVertical)
            {
                // 选择中间两行的某一列
                midId1 = midRow * colCount + midCol;
                midId2 = (midRow - 1) * colCount + midCol;
            }
            else
            {
                // 选择中间两列的某一行
                midId1 = midRow * colCount + midCol;
                midId2 = midRow * colCount + (midCol - 1);
            }

            // 交换midId2的位置
            Item mid1Item = items[midId1];
            Item mid2Item = items[midId2];
            if (mid1Item.iconId != mid2Item.iconId)
            {
                for (int i = 0; i < count; i++)
                {
                    var item = items[i];
                    if (item.id == midId1 || item.id == midId2) continue;
                    if (item.iconId == mid1Item.iconId)
                    {
                        int itemId = item.id;
                        item.id = mid2Item.id;
                        mid2Item.id = itemId;
                        items[midId2] = item;
                        items[i] = mid2Item;

                        // 设置状态
                        mid1Item.status = EItemStatus.Unlocked;
                        item.status = EItemStatus.Unlocked;
                        break;
                    }
                }
            }
            else
            {
                mid1Item.status = EItemStatus.Unlocked;
                mid2Item.status = EItemStatus.Unlocked;
            }

            // 为每个格子指定其相邻的格子（上下左右）
            for (int i = 0; i < count; i++)
            {
                int row = i / colCount; // 计算当前格子的行号
                int col = i % colCount; // 计算当前格子的列号

                Item item = items[i];

                // 计算左侧相邻格子的ID
                item.left = (col - 1) < 0 ? -1 : i - 1;

                // 计算右侧相邻格子的ID
                item.right = (col + 1) >= colCount ? -1 : i + 1;

                // 计算上方相邻格子的ID
                item.top = (row - 1) < 0 ? -1 : i - colCount;

                // 计算下方相邻格子的ID
                item.bottom = (row + 1) >= rowCount ? -1 : i + colCount;

                //LogManager.Log($"{item.id} --- 上:{item.top} 下:{item.bottom} 左:{item.left} 右:{item.right}  iconId:{item.iconId} status:{item.status}", "GameDataMgr");
            }

            // 再找两张中间的并直接设置解锁
            Item newMid1Item = items[midId1];
            Item newMid2Item = items[midId2];
            if (isVertical)
            {
                if (newMid1Item.left != -1) items[newMid1Item.left].status = EItemStatus.Unlocked;
                else if (newMid1Item.right != -1) items[newMid1Item.right].status = EItemStatus.Unlocked;

                if (newMid2Item.left != -1) items[newMid2Item.left].status = EItemStatus.Unlocked;
                else if (newMid2Item.right != -1) items[newMid2Item.right].status = EItemStatus.Unlocked;
            }
            else
            {
                if (newMid1Item.top != -1) items[newMid1Item.top].status = EItemStatus.Unlocked;
                else if (newMid1Item.bottom != -1) items[newMid1Item.bottom].status = EItemStatus.Unlocked;

                if (newMid2Item.top != -1) items[newMid2Item.top].status = EItemStatus.Unlocked;
                else if (newMid2Item.bottom != -1) items[newMid2Item.bottom].status = EItemStatus.Unlocked;
            }

            EventCenter.Instance.Trigger(GameEventName.OnLifeCountChanged, lifeRemainNum);
        }

        public int GetItemCount()
        {
            var dimensions = layout.Split('x');
            var colums = int.Parse(dimensions[0]);
            var rows = int.Parse(dimensions[1]);

            // 验证总数是否为偶数
            return rows * colums;
        }

        public int GetTotalCol()
        {
            var dimensions = layout.Split('x');
            return int.Parse(dimensions[0]);
        }

        public int GetTotalRow()
        {
            var dimensions = layout.Split('x');
            return int.Parse(dimensions[1]);
        }

        /// <summary>消除Item</summary>
        public List<int> DestroyItem(Item item)
        {
            item.status = EItemStatus.Destroyed;
            List<int> result = new List<int>();

            // 改变邻居的状态
            CheckAndChangeStatus(item.top, result);
            CheckAndChangeStatus(item.bottom, result);
            CheckAndChangeStatus(item.left, result);
            CheckAndChangeStatus(item.right, result);
            destroyedCount++;
            return result;

            void CheckAndChangeStatus(int id, List<int> result)
            {
                if (id != -1 && items[id].status == EItemStatus.Locked)
                {
                    items[id].status = EItemStatus.Unlocked;
                    result.Add(id);
                }
            }
        }

        /// <summary>
        /// 打乱所有状态为Unlocked的格子
        /// </summary>
        /// <returns>返回打乱前后的格子ID对应关系列表</returns>
        public List<(int sourceId, int targetId)> ShuffleUnlockedItems()
        {
            // 获取所有状态为Unlocked的格子
            var unlockedItems = items.Where(item => item.status == EItemStatus.Unlocked).ToList();

            // 如果没有Unlocked的格子，直接返回空列表
            if (unlockedItems.Count == 0)
                return new List<(int, int)>();

            // 保存原始ID和图标ID的映射关系
            var originalIconMap = unlockedItems.ToDictionary(item => item.id, item => item.iconId);

            // 提取所有Unlocked格子的图标ID
            var iconIds = unlockedItems.Select(item => item.iconId).ToList();

            // 打乱图标ID的顺序
            System.Random random = new System.Random();
            var shuffledIconIds = iconIds.OrderBy(x => random.Next()).ToList();

            // 创建结果列表
            var result = new List<(int, int)>();

            // 将打乱后的图标ID重新分配给Unlocked格子
            for (int i = 0; i < unlockedItems.Count; i++)
            {
                // 找到原来拥有这个图标ID的格子ID
                var sourceId = originalIconMap.FirstOrDefault(x => x.Value == shuffledIconIds[i]).Key;

                // 设置当前格子的新图标ID
                unlockedItems[i].iconId = shuffledIconIds[i];

                // 添加到结果列表
                result.Add((sourceId, unlockedItems[i].id));
                originalIconMap.Remove(sourceId);
            }

            GameDataMgr.Instance.Save();
            return result;
        }

        /// <summary>更新错误次数</summary>
        public void UpdateLifeRemainNum(int count)
        {
            if (GameDataMgr.Instance.IsUnlockErrorLimit())
            {
                if (GameDataMgr.Instance.IsUnlockTimeLimit() && count >= 3)
                    remainSeconds = GetTimeLimitLen();

                // 减小生命数量
                lifeRemainNum = UnityEngine.Mathf.Clamp(lifeRemainNum + count, 0, 99);
                EventCenter.Instance.Trigger(GameEventName.OnLifeCountChanged, lifeRemainNum);
            }
        }

        /// <summary>当前关卡是否胜利</summary>
        public bool IsLevelWin() => destroyedCount == GetItemCount();

        /// <summary>找到可用消除的两个格子</summary>
        public (int id1, int id2) FindCanDestroyTwoItems(PathFinder finder)
        {
            var unlockedItems = items.Where(item => item.status == EItemStatus.Unlocked).ToArray();
            for (int i = 0; i < unlockedItems.Length; i++)
            {
                for (int j = i + 1; j < unlockedItems.Length; j++)
                {
                    var path = finder.FindPath(unlockedItems[i], unlockedItems[j], this);
                    if (path != null && path.Count > 0)
                    {
                        return (unlockedItems[i].id, unlockedItems[j].id);
                    }
                }
            }
            return (-1, -1);
        }

        /// <summary>炸弹，炸出已解锁周围的4个</summary>
        public List<int> Bomb()
        {
            List<int> result = new List<int>();

            // 找到所有已解锁的格子
            var unlockedItems = items.Where(item => item.status == EItemStatus.Unlocked).ToArray();

            int maxCount = 4;
            // 遍历所有已解锁的格子
            foreach (var item in unlockedItems)
            {
                if (item.top != -1 && items[item.top].status == EItemStatus.Locked)
                {
                    result.Add(item.top);
                    if (result.Count >= maxCount) break;
                }
                if (item.bottom != -1 && items[item.bottom].status == EItemStatus.Locked)
                {
                    result.Add(item.bottom);
                    if (result.Count >= maxCount) break;
                }
                if (item.left != -1 && items[item.left].status == EItemStatus.Locked)
                {
                    result.Add(item.left);
                    if (result.Count >= maxCount) break;
                }
                if (item.right != -1 && items[item.right].status == EItemStatus.Locked)
                {
                    result.Add(item.right);
                    if (result.Count >= maxCount) break;
                }
            }

            // 改变状态
            foreach (var id in result)
                items[id].status = EItemStatus.Unlocked;
            return result;
        }

        public Dictionary<int, AssetInfo> GetCurAssetsInfo()
        {
            Dictionary<int, AssetInfo> result = new Dictionary<int, AssetInfo>();
            if (assetsInfo != null)
            {
                for (int i = 0; i < assetsInfo.Count; i++)
                {
                    var info = assetsInfo[i];
                    if (info.rawUrl != null && info.smallUrl != null)
                    {
                        result.Add(info.id, info);
                    }
                }
            }

            return result;
        }
    }

    // 单个格子数据
    [MessagePackObject]
    public class Item
    {
        [Key(0)] public int id;                     // 格子的id，从0开始
        [Key(1)] public int iconId;                 // 格子图标id
        [Key(2)] public EItemStatus status;         // 当前格子的状态
        [Key(3)] public int left;                  // 当前格子的左边格子（如果没有就是null，比如处于边界的格子）
        [Key(4)] public int right;                 // 当前格子的右边格子（如果没有就是null，比如处于边界的格子）
        [Key(5)] public int top;                   // 当前格子的上边格子（如果没有就是null，比如处于边界的格子）
        [Key(6)] public int bottom;                // 当前格子的下边格子（如果没有就是null，比如处于边界的格子）
    }

    // 图片信息
    [MessagePackObject]
    public class AssetInfo
    {
        [Key(0)] public int id;                         // 资源的id
        [Key(1)] public EAssetType type;                // 资源类型
        [Key(2)] public string smallUrl;                // 缩略图下载地址
        [Key(3)] public string rawUrl;                  // 原图/视频下载地址

        public AssetInfo Clone()
        {
            return MemberwiseClone() as AssetInfo;
        }
    }
}